#!/bin/bash

# http://www.hackerzvoice.net/hzvault/
# ce script installe hzvault sur une clef ou un disque dur.

#########################
# PRELIMINAIRES
#########################

# valeurs par defaut. Valides pour le script
DEFAULT_DEBIAN_VERSION="squeeze"
#DEFAULT_LINUX_IMAGE="linux-image-686"
DEFAULT_NOT_VERBOSE_OUTPUT="./hzvault.lastlog"
DEFAULT_VERBOSE_OUTPUT="/dev/stdout"
DEFAULT_MAX_KEYSIZE=2000000000
DEFAULT_APT_PROXY_ADDRESS="http://localhost:3142/debian"
DEFAULT_APT_PROXY_DIR="/var/cache/apt-cacher-ng"
DEFAULT_DEBOOTSRAP_CACHE_DIR="/tmp/debootsrap_cache"
HEIGHT=50
WIDTH=70
CRYPTO=1
VIRT=1

# catch CTRL-C
trap "echo ''; echo vous avez tapé CTRL-C. Exit!; exit 1" 2  

# test les parametres entres
# parametre 1 doit etre un peripherique bloc et ne doit pas contenir de caractere numerique
# verifie au passage que la clef est presente
[ -b $1 ] || usage
TEMP=$(echo $1 | grep [0-9])
[ -z $TEMP ] || usage
[ -z $1 ] && usage
KEYPATH=$1
shift

VERB=$DEFAULT_NOT_VERBOSE_OUTPUT 
# mode verbose
# par defaut: non verbose
# si parametre 2 est -v alors passe en mode verbose 
VERB=$DEFAULT_NOT_VERBOSE_OUTPUT 
while [ "$1" ]; do
[ ! -z $1 ] && [ $1 = "-v" ] && VERB=$DEFAULT_VERBOSE_OUTPUT && echo "mode verbose actif" 2>>$VERB 1>>$VERB
[ ! -z $1 ] && [ $1 = "--verbose" ] && VERB=$DEFAULT_VERBOSE_OUTPUT && echo "mode verbose actif"  2>>$VERB 1>>$VERB
[ ! -z $1 ] && [ $1 = "--debug" ] && set -v && echo "mode debug actif"  2>>$VERB 1>>$VERB
#[ ! -z $1 ] && [ $1 = "--no-crypto" ] && CRYPTO=0 && echo "Pas de crypto logicielle" 2>>$VERB 1>>$VERB
#[ ! -z $1 ] && [ $1 = "--no-virtualization" ] && VIRT=0 && echo "Pas de virtualisation" 2>>$VERB 1>>$VERB
  shift
done

if ( dpkg -s dialog 2>>$VERB | grep "Status: install ok ">/dev/null );
then
[ $(id -u) -ne "0" ] && echo "Vous devez etre sudo pour lancer ce script." && exit 1
else
    if ( dpkg -s dialog | grep "Status: install ok ">/dev/null )
    then 
    echo "Package dialog found." 2>>$VERB 1>>$VERB
    else
    echo "Installation of dialog" 2>>$VERB 1>>$VERB
    apt-get install -y dialog 2>>$VERB 1>>$VERB
    fi
fi

# arrete le script, affiche un message d'erreur et usage
erreur() {
  dialog --title "| Erreur |" --msgbox "\
  \n \
  $1 \n\n \
  Sortie du programme...\n \
  " $HEIGHT $WIDTH 
  echo ""
  set -e
  exit 1
}

# usage
usage() {
  dialog --title "| HZVault : usage |" --msgbox " \
  Usage:\n \
 $0 disque\n \
 $0 disque -v\n\n \
  Ex:\n \
 \"$ sudo $0 /dev/sdb\"\n\n \
  liste des disques:\n \
  \
  $(fdisk -l | grep Dis | sed -e 's/Dis/\\n  Dis/') \
  " $HEIGHT $WIDTH
  echo ""
  exit 1
}

# message d'accueil
dialog --title "| /!\ Effacement des données /!\ |" --defaultno --yesno "Attention, la clef $KEYPATH sera totalement effacee.\n\nContinuer ?" $HEIGHT $WIDTH
[ $? = 1 ] && erreur "Reponse \"oui\" necessaire pour continuer."

# recuperation du chemin et taille de la clef
KEYSIZE=$(fdisk -l $KEYPATH | grep $KEYPATH: | cut -f 5 -d ' ')

# test si cle suffisamment grande
[ "$KEYSIZE" -le $DEFAULT_MAX_KEYSIZE ] && erreur "Clef trop petite. Choisir une clef de taille superieure a 2GB"

# installation paquets sur debian
for i in cryptsetup lvm2 initramfs-tools dosfstools debootstrap parted dcfldd ntfsprogs
do
    if ( dpkg -s $i | grep "Status: install ok ">/dev/null )
    then 
    echo "Package $i found." 2>>$VERB 1>>$VERB
    else
    echo "Installation of $i" 2>>$VERB 1>>$VERB
    apt-get install -y $i 2>>$VERB 1>>$VERB
fi
done
# apt-get install hashalot

# activation des modules necessaires
modprobe aes-i586
modprobe dm-crypt

# utilisation de apt-proxy?
APT_PROXY=""
dialog --title "| Apt-cacher |" --yesno "Souhaitez-vous utiliser apt-cacher ? \n\nApt-cacher permet de conserver les packages afin de les réutiliser pour une future installaiton. Il est recommandé d'utiliser apt-cacher si vous souhaitez installer plusieurs disques HZVault." 100 100 
if [ $? -eq 0 ]
then
    if ( dpkg -s apt-cacher-ng | grep "Status: install ok ">/dev/null )
    then
    APT_PROXY=$DEFAULT_APT_PROXY_ADDRESS
    else
    echo "Installation of apt-cacher" 2>>$VERB 1>>$VERB
    apt-get install apt-cacher-ng 2>>$VERB 1>>$VERB
    APT_PROXY=$DEFAULT_APT_PROXY_ADDRESS
    fi
fi

#########################
# NETTOYAGE
#########################

# demontage
umount /mnt/chroot/dev/pts 2>>$VERB 1>>$VERB
umount /mnt/chroot/dev 2>>$VERB 1>>$VERB 
umount /mnt/chroot/sys 2>>$VERB 1>>$VERB
umount /mnt/chroot/boot 2>>$VERB 1>>$VERB
umount /mnt/chroot/proc 2>>$VERB 1>>$VERB
umount /mnt/chroot/tools 2>>$VERB 1>>$VERB
umount /mnt/chroot/tmp/lib 2>>$VERB 1>>$VERB
umount /mnt/chroot$DEFAULT_APT_PROXY_DIR 2>>$VERB 1>>$VERB
umount /mnt/chroot/ 2>>$VERB 1>>$VERB
umount /dev/mapper/vghzvault-rootfs 2>>$VERB 1>>$VERB
umount /dev/mapper/vghzvault-swap 2>>$VERB 1>>$VERB
umount /dev/mapper/pvhzvault 2>>$VERB 1>>$VERB
umount /dev/mapper/data 2>>$VERB 1>>$VERB

# fermeture du groupe lvm
vgchange -an vghzvault 2>>$VERB 1>>$VERB

# suppression des partitions LVM (au cas ou) 
lvremove -f /dev/mapper/vghzvault-rootfs 2>>$VERB 1>>$VERB
lvremove -f /dev/mapper/vghzvault-swap 2>>$VERB 1>>$VERB

# suppression du groupe LVM (au cas ou) 
vgremove -f vghzvault 2>>$VERB 1>>$VERB

# suppression du disque physique LVM (au cas ou)
pvremove -f /dev/mapper/pvhzvault 2>>$VERB 1>>$VERB

# Fermeture des partitions luks
cryptsetup luksClose pvhzvault 2>>$VERB 1>>$VERB
cryptsetup luksClose data 2>>$VERB 1>>$VERB

# wipe des partitions luks
cryptsetup remove pvhzvault 2>>$VERB 1>>$VERB
cryptsetup remove data 2>>$VERB 1>>$VERB

# supprime le repertoire /dev/mapper/pvhzvault
rm /dev/mapper/pvhzvault 2>>$VERB 1>>$VERB
rm /dev/mapper/vghzvault* 2>>$VERB 1>>$VERB
rm /dev/mapper/data 2>>$VERB 1>>$VERB

# demontage des partitions de la cle deja montees
umount ${KEYPATH}* 2>>$VERB 1>>$VERB

#########################
# PARTITIONNEMENT
#########################

# tailles par defaut
# taille totale de la clef en Mo
(( SIZE_Mo=$KEYSIZE/1000000 ))
# taille du bootloader
(( PART1=100 ))
# taille des tools
(( PART4=100 ))
# taille de rootfs
(( PART2A=($SIZE_Mo - $PART1 - $PART4) / 2 ))
# taille de swap (maxi 512 Mo)
(( PART2B=($SIZE_Mo - $PART1 - $PART4) / 20 ))
(( PART2A=$PART2A - $PART2B ))
[ $PART2B -gt 512 ] && (( PART2B=512 ))
# taille de data
(( PART3=$SIZE_Mo - $PART1 - $PART4 - $PART2A - $PART2B ))
# a combien de Mo du debut de la cle se trouve data
(( DEBUT3=$PART1+$PART2A+$PART2B ))
# a combien de Mo du debut de la cle se trouve tools
(( DEBUT4=$PART1+$PART2A+$PART2B+$PART3 ))

# partition() propose a l'utilisateur de modifier les tailles par defaut
partition() {
  # data
  (( PART3=$SIZE_Mo - $PART1 - $PART4 - $PART2A - $PART2B ))

  dialog --title "| Partitionnement |" --yesno " \
  Clef de $SIZE_Mo Mo \n\n \
  Table de partition proposee: \n \
  ${KEYPATH}1- bootloader $PART1 \n \
  ${KEYPATH}2- (chiffre) LVM pvhzvault - rootfs: $PART2A \n \
  ${KEYPATH}2- (chiffre) LVM pvhzvault - swap: $PART2B \n \
  ${KEYPATH}3- (chiffre) data $PART3 \n \
  ${KEYPATH}4- tools $PART4 \n\n \
  Accepter cette table de partition ? \
  " $HEIGHT $WIDTH 
  # return 0: partition acceptee, sortie de la fonction
  [ $? = 0 ] && return 0

  # rootfs
  # calcul de la taille maximale autorisee pour la partition rootfs
  (( MAX1_Mo=$SIZE_Mo - $PART1 - $PART4 - 50 - 100 ))
  # dialog
  dialog --title "| Partitionnement |" --inputbox " \
  rootfs \n\n \
  rootfs contient HZVault et les differents systemes d'exploitation \n \
  Quelle taille pour rootfs (en Mo)? \n \
  (300-$MAX1_Mo) [$PART2A] \
  " $HEIGHT $WIDTH $PART2A 2>TMP 
  RESPONSE=$(cat TMP)
  rm TMP
  # si la reponse est vide, lui donner la valeur par defaut
  [ -z $RESPONSE ] && RESPONSE=$PART2A
  # test si reponse est un entier
  [ ! "$(echo $RESPONSE | grep "^[ [:digit:] ]*$")" ] && dialog --title "partitionnement" --msgbox "reponse invalide" $HEIGHT $WIDTH && return 1 
  # si reponse plus petite que 300 ou plus grande que MAX1_Mo alors return 1
  [ $RESPONSE -lt 300 -o $RESPONSE -gt $MAX1_Mo ] && dialog --title "partitionnement" --msgbox "reponse invalide" $HEIGHT $WIDTH && return 1
  # changer la valeur de PART2A
  ((PART2A=$RESPONSE))

  # swap
  # calcul de la taille maximale autorisee pour la partition swap (maxi 512 Mo)
  (( MAX2_Mo=$SIZE_Mo - $PART1 - $PART4 - $PART2A - 100))
  [ $MAX2_Mo -gt 512 ] && (( MAX2_Mo=512 ))
  # la taille de la swap par defaut proposee doit etre inferieure a MAX2_Mo
  [ $PART2B -gt $MAX2_Mo ] && PART2B=$MAX2_Mo
  dialog --title "| Partitionnement |" --inputbox " \
  swap \n\n\n \
  Quelle taille pour le swap (en Mo)? \n \
  (50-$MAX2_Mo) [$PART2B]: \
  " $HEIGHT $WIDTH $PART2B 2>TMP
  RESPONSE=$(cat TMP)
  rm TMP
  # si la reponse est vide, lui donner la valeur par defaut
  [ -z $RESPONSE ] && RESPONSE=$PART2B
  # test si reponse est un entier
  [ ! "$(echo $RESPONSE | grep "^[ [:digit:] ]*$")" ] && dialog --title "partitionnement" --msgbox "reponse invalide" $HEIGHT $WIDTH && return 1 
  # si reponse plus petite que 50 ou plus grande que MAX2_Mo alors return 1
  [ $RESPONSE -lt 50 -o $RESPONSE -gt $MAX2_Mo ] && dialog --title "partitionnement" --msgbox "reponse invalide" $HEIGHT $WIDTH && return 1
  # changer la valeur de PART2B et de PART3
  ((PART2B=$RESPONSE))
  return 1
}

# boucle pour que l'utilisateur choisisse son partitionnement
while true; do
   partition  && break
done

dialog --title "| Partitionnement |" --infobox "debut du partionnement" $HEIGHT $WIDTH
for i in 1 2 3 4
do
if ( parted -l -m 2>>$VERB | grep -A 4 $KEYPATH | grep "^$i" >>$VERB) 
then
 parted -s $KEYPATH "rm $i" 2>>$VERB 1>>$VERB || erreur "Erreur fatale lors de la suppression de la table de partition."
fi
done
parted -s $KEYPATH "mklabel msdos mkpart primary ext2 1 ${PART1}.0Mb mkpart primary ${PART1}.0Mb ${DEBUT3}.0Mb mkpart primary ${DEBUT3}.0Mb ${DEBUT4}.0Mb mkpart primary fat32 ${DEBUT4}.0Mb -0 set 1 boot on" 2>>$VERB 1>>$VERB ||  erreur "Erreur fatale lors de la creation de la table de partition."

# partition de boot
mkfs.ext2 ${KEYPATH}1 2>>$VERB 1>>$VERB

# activation crypto
dialog --title "| Chiffrement |" --yesno "Souhaitez vous activer le chiffrement du disque ?" $HEIGHT $WIDTH
[ $? = 1 ] && CRYPTO=0

if [ ! $CRYPTO = "0" ] 
then
  # wipe des deux partitions chiffrees
  dialog --title "| Wipe |" --defaultno  --yesno "Wiper le disque\n\n\nSi vous souhaitez wiper vos partitions avant de les chiffrer (operation longue!), choisissez \"oui\". Si vous préférez ne pas wiper, choisissez \"non\"." $HEIGHT $WIDTH
  [ $? != 1 ] && dcfldd if=/dev/urandom of=${KEYPATH}2 && dcfldd if=/dev/urandom of=${KEYPATH}3
  # partition systeme et swap
  dialog --title "| Chiffrement |" --infobox "Chiffrement de ${KEYPATH}2 pour les futures partitions rootfs et swap" $HEIGHT $WIDTH

  # chiffrement. test si les mots de passe entres matchent. Sinon, recommence
  dialog --title "| Chiffrement |" --infobox "Creation de la partition chiffree ${KEYPATH}2" $HEIGHT $WIDTH
  j=5
  while (($j > 0)) 
  do
    ( cryptsetup -y -q --cipher aes-cbc-essiv:sha256 --key-size 256 luksFormat ${KEYPATH}2 2>>$VERB 1>>$VERB ) && break 
    j=$j-1
  done
  if (($j == 0)); then erreur "Impossible de créer la partition ${KEYPATH}2"; fi
  
  # ouverture. test si le mot de passe est correct. Sinon, recommence
  dialog --title "| Chiffrement |" --infobox "Ouverture de la partition chiffree ${KEYPATH}2" $HEIGHT $WIDTH
  j=5
  while (($j > 0))
  do
    ( cryptsetup -q luksOpen ${KEYPATH}2 pvhzvault 2>>$VERB 1>>$VERB ) && break
    j=$j-1
  done
  if (($j == 0)); then erreur "Impossible d'ouvrir /dev/mapper/vghzvault"; fi

  # Creation du LVM 
  # Le LVM permet de redimensionner les volumes à chaud et d’effectuer des snapshot à chaud de votre volume.
  # remarque: pour supprimer une partition LVM: lvremove /dev/mapper/lvm--hzvault-rootfs

  # creation du disque et du groupe LVM
  pvcreate -f /dev/mapper/pvhzvault 2>>$VERB 1>>$VERB
  vgcreate vghzvault /dev/mapper/pvhzvault 2>>$VERB 1>>$VERB
else
  pvcreate -f ${KEYPATH}2 2>>$VERB 1>>$VERB
  vgcreate vghzvault ${KEYPATH}2 2>>$VERB 1>>$VERB
fi

# creation de la partition rootfs
#lvcreate -n rootfs -L ${PART2A}M vghzvault 2>>$VERB 1>>$VERB

# creation de la partition swap
#lvcreate -n swap -l 100%FREE vghzvault 2>>$VERB 1>>$VERB
lvcreate -n swap -L ${PART2B}M vghzvault 2>>$VERB 1>>$VERB
lvcreate -n rootfs -l 100%FREE vghzvault 2>>$VERB 1>>$VERB

# formatage partitions lvm rootfs et swap
mkfs.ext2 /dev/mapper/vghzvault-rootfs 2>>$VERB 1>>$VERB
mkswap /dev/mapper/vghzvault-swap 2>>$VERB 1>>$VERB

# chiffrement et formatage de la partition data
dialog --title "| Chiffrement |" --infobox "Chiffrement et formatage de ${KEYPATH}3 (data)" $HEIGHT $WIDTH
if [ ! $CRYPTO = "0" ]
then
  dialog --title "| Chiffrement |" --infobox "Chiffrement de la partition ${KEYPATH}3" $HEIGHT $WIDTH
  while true; do
    ( cryptsetup -y -q --cipher aes-cbc-essiv:sha256 --key-size 256 luksFormat ${KEYPATH}3 2>>$VERB 1>>$VERB ) && break
  done
  dialog --title "| Chiffrement |" --infobox "Ouverture de la partition chiffree ${KEYPATH}3" $HEIGHT $WIDTH
  while true; do
    ( cryptsetup -q luksOpen ${KEYPATH}3 data 2>>$VERB 1>>$VERB ) && break
  done
  mkntfs -f /dev/mapper/data 2>>$VERB 1>>$VERB
else
  mkntfs -f ${KEYPATH}3 2>>$VERB 1>>$VERB
fi

# formatage de la partition tools
mkfs.vfat ${KEYPATH}4 2>>$VERB 1>>$VERB


#########################
# CHROOT
#########################

# montage des partitions pour le chroot
mkdir /mnt/chroot/ 2>>$VERB 1>>$VERB
mount /dev/mapper/vghzvault-rootfs /mnt/chroot 2>>$VERB 1>>$VERB
mkdir /mnt/chroot/boot 2>>$VERB 1>>$VERB
mount ${KEYPATH}1 /mnt/chroot/boot 2>>$VERB 1>>$VERB
mkdir /mnt/chroot/tools
mount ${KEYPATH}4 /mnt/chroot/tools 2>>$VERB 1>>$VERB
mkdir -p /mnt/chroot/var/cache/apt-cacher-ng
mount -o bind /var/cache/apt-cacher-ng /mnt/chroot/var/cache/apt-cacher-ng 2>>$VERB 1>>$VERB

#########################
# Installation du systeme de base
#########################

echo "Lancement du debootstrap" 2>>$VERB 1>>$VERB
DEBIAN_VERSION=$DEFAULT_DEBIAN_VERSION

# SANS USPLASH
debootstrap --verbose --include='initramfs-tools,lvm2,dmsetup,cryptsetup,hashalot,initramfs-tools,vim,busybox,ruby,libqt4-ruby,less,debconf,locales,patch' $DEBIAN_VERSION /mnt/chroot $APT_PROXY 2>>$VERB 1>>$VERB 

#debootstrap --verbose --include='initramfs-tools,lvm2,usplash,dmsetup,cryptsetup,hashalot,initramfs-tools,vim,busybox,ruby,libqt4-ruby,less,debconf,locales,patch' $DEBIAN_VERSION /mnt/chroot $APT_PROXY 2>>$VERB 1>>$VERB 

# activation virtualisation
dialog --title "| Virtualisation |" --yesno "Souhaitez vous installer le systeme de virtualisation? \n \
(Sans virtualisation, vous ne pourrez pas lancer plusieurs OS depuis la clef.)" $HEIGHT $WIDTH
[ $? = 1 ] && VIRT=0

# Monter /dev et /proc dans le chroot
mount -o bind /dev/ /mnt/chroot/dev 2>>$VERB 1>>$VERB

# Monter ./hzvault/lib dans le /tmp du chroot
mkdir -p /mnt/chroot/tmp/lib 2>>$VERB 1>>$VERB
mount -o bind ./lib /mnt/chroot/tmp/lib 2>>$VERB 1>>$VERB

# attribution des droits d'execution au script ./lib/install2.sh
chmod +x ./lib/install2.sh 2>>$VERB 1>>$VERB

#########################################
# Execution du script ./lib/install2.sh #
#########################################

# Se chrooter dans le chemin /mnt/chroot et lancer le script install2.sh
chroot /mnt/chroot /tmp/lib/install2.sh $KEYPATH $VERB $DEBIAN_VERSION $DEFAULT_NOT_VERBOSE_OUTPUT $DEFAULT_VERBOSE_OUTPUT $DEFAULT_APT_PROXY_DIR $CRYPTO $VIRT $APT_PROXY

##########################
# retour dans install.sh #
##########################

# Quitter le chroot
# Demontage de tous les points de montage
umount /mnt/chroot/dev/pts 2>>$VERB 1>>$VERB
umount /mnt/chroot/dev 2>>$VERB 1>>$VERB 
umount /mnt/chroot/sys 2>>$VERB 1>>$VERB
umount /mnt/chroot/boot 2>>$VERB 1>>$VERB
umount /mnt/chroot/proc 2>>$VERB 1>>$VERB
umount /mnt/chroot/tools 2>>$VERB 1>>$VERB
umount /mnt/chroot/tmp/lib 2>>$VERB 1>>$VERB
umount /mnt/chroot$DEFAULT_APT_PROXY_DIR 2>>$VERB 1>>$VERB
umount /mnt/chroot/ 2>>$VERB 1>>$VERB

# fermeture du groupe lvm
vgchange -an vghzvault 2>>$VERB 1>>$VERB

# Fermeture des partitions luks
cryptsetup luksClose pvhzvault 2>>$VERB 1>>$VERB
cryptsetup luksClose data 2>>$VERB 1>>$VERB

# demontage des partitions de la cle deja montees
umount ${KEYPATH}* 2>>$VERB 1>>$VERB

#EOF
